package com.java.laixiangdong.express.dao;

import com.java.laixiangdong.express.bean.Express;
import com.java.laixiangdong.express.bean.ExpressPlace;
import jdk.jshell.ExpressionSnippet;

import javax.imageio.IIOException;
import java.io.*;
import java.net.Socket;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Random;

/**
 * 改为map和set去存储快递对象
 * <p>
 * 分析：
 * 快递对象是不可以重复的，以单号为依据
 * 位置不能重复,且要与快递对象绑定，所以需要新建一个位置类
 * 以快递对象为键，位置对象为值
 * 位置对象再用set来去重
 */
public class Dao {
    // m, n 为快递柜的行数，列数
    private static final int m = 10;
    private static final int n = 10;
    private static HashMap<Express, ExpressPlace> expresses = new HashMap<>();
    private static HashSet<ExpressPlace> expressPlaces = new HashSet<>();

    public static void setExpresses(HashMap<Express, ExpressPlace> expresses) {
        Dao.expresses = expresses;
    }

    public static HashSet<ExpressPlace> getExpressPlaces() {
        return expressPlaces;
    }

    public static void setExpressPlaces(HashSet<ExpressPlace> expressPlaces) {
        Dao.expressPlaces = expressPlaces;
    }

    // 空余快递数
    private static int size = m * n;

    private Dao() {
    }

    private static Dao dao = new Dao();

    public static Dao getInstance() {
        return dao;
    }

    private Random r = new Random();


    /**
     * 判断是否有这个单号
     *
     * @param odd 单号
     * @return 有返回真
     */
    public Boolean hasOdd(int odd) {
        /*
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (expresses[i][j] != null && expresses[i][j].getOdd() == odd) {
                    return true;
                }
            }
        }
        */
        for (Express e : expresses.keySet()) {
            if (e.getOdd() == odd)
                return true;
        }
        return false;
    }

    /**
     * 创建快递对象并存入数组
     *
     * @param odd     单号
     * @param company 公司名称
     * @return 快递对象
     */
    public Express newExpress(int odd, String company) {
        int i = r.nextInt(m);
        int j = r.nextInt(n);

        // 如果此位置已有快递就重新调用生成新的位置
        // 会生成随机取件码，如果重复重新生成
        /*
        if (expresses[i][j] == null) {
            int code;
            out:
            while (true) {
                code = r.nextInt(899999) + 100000;
                for (Express[] express : expresses) {
                    for (Express e : express) {
                        if (e != null && e.getCode() == code) {
                            continue out;
                        }
                    }
                }
                break;
            }
            expresses[i][j] = new Express(odd, code, company);
            size--;
            System.out.println("请把快递放在第" + (i + 1) + "行，第" + (j + 1) + "列");
            return expresses[i][j];
        } else if (size > 0) { //有空位
            return newExpress(odd, company);
        } else { //快递已满
            System.out.println("快递已满");
            return null;
        }
        */
        ExpressPlace ep = new ExpressPlace(i, j);
        if (expressPlaces.add(ep)) {
            int code;
            Express express;
            out:
            while (true) {
                code = r.nextInt(899999) + 100000;
                for (Express e : expresses.keySet()) {
                    if (e.getCode() == code)
                        continue out;
                }
                express = new Express(odd, code, company);
                break;
            }
            expresses.put(express, ep);
            System.out.println("请把快递放在第" + (i + 1) + "行，第" + (j + 1) + "列");
            return express;
        } else if (size > 0) {
            return newExpress(odd, company);
        } else {
            System.out.println("快递已满");
            return null;
        }
    }

    /**
     * 删除数组中的快递对象
     *
     * @param odd 单号
     * @return 删除成功为真
     */
    public Boolean remove(int odd) {
        /*
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (expresses[i][j] != null && expresses[i][j].getOdd() == odd) {
                    System.out.println("请把快递第" + (i + 1) + "行，第" + (j + 1) + "列取走");
                    expresses[i][j] = null;
                    return true;
                }
            }
        }
        */
        for (Express e : expresses.keySet()) {
            if (e.getOdd() == odd) {
                int i = expresses.get(e).getM();
                int j = expresses.get(e).getN();
                System.out.println("请把快递第" + (i + 1) + "行，第" + (j + 1) + "列取走");
                expressPlaces.remove(expresses.get(e));
                expresses.remove(e);
                return true;
            }
        }
        return false;
    }

    /**
     * 通过单号获取快递对象
     *
     * @param odd 单号
     * @return 快递对象
     */
    public Express searchExpress(int odd) {
        /*
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (expresses[i][j] != null && expresses[i][j].getOdd() == odd) {
                    return expresses[i][j];
                }
            }
        }
        */
        for (Express e : expresses.keySet()) {
            if (e.getOdd() == odd) {
                return e;
            }
        }
        return null;
    }

    /**
     * 通过取件码获取快递单号
     *
     * @param code 取件码
     * @return 快递单号
     */
    public int getExpressOddByCode(int code) {
        /*
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (expresses[i][j] != null && expresses[i][j].getCode() == code) {
                    return expresses[i][j].getOdd();
                }

            }
        }
        */
        for (Express e : expresses.keySet()) {
            if (e.getCode() == code) {
                return e.getOdd();
            }
        }
        return -1;
    }

    /**
     * 遍历打印所有快递
     */
    public void showAllExpress() {
        int count = 0;
        /*
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (expresses[i][j] != null) {
                    System.out.print((i+1)+"行-"+(j+1)+"列\t");
                    System.out.println(expresses[i][j].toString());
                    count++;
                }
            }
        }
        */
        for (Express e : expresses.keySet()) {
            int i = expresses.get(e).getM();
            int j = expresses.get(e).getN();
            System.out.print((i + 1) + "行-" + (j + 1) + "列\t");
            System.out.println(e.toString());
            count++;
        }
        if (count == 0) {
            System.out.println("当前没有任何快递");
        }

    }

    // 新增获取map数据方法
    public static HashMap<Express, ExpressPlace> getExpresses() {
        return expresses;
    }

    /**
     * 序列化expresses对象，expressPlaces对象
     */
    public void saveFile() throws IOException {
        Socket socket = new Socket("127.0.0.1", 56601);
        OutputStream outputStream = socket.getOutputStream();
        try (ObjectOutputStream expressesOutput = new ObjectOutputStream(outputStream)) {
            expressesOutput.writeObject(Dao.expresses);
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("保存expresses失败");
        }
        Socket socket2 = new Socket("127.0.0.1", 56603);
        OutputStream outputStream2 = socket2.getOutputStream();
        try (ObjectOutputStream expressPlacesOutput = new ObjectOutputStream(outputStream2)) {
            expressPlacesOutput.writeObject(Dao.expressPlaces);
        } catch (IOException e) {
            System.out.println("保存expressPlaces失败");
        }

    }

    public void readFile() throws IOException {

        Socket socket = new Socket("127.0.0.1", 56602);
        InputStream inputStream = socket.getInputStream();
        try (ObjectInputStream expressesInput = new ObjectInputStream(inputStream)) {
            Dao.expresses = (HashMap<Express, ExpressPlace>) expressesInput.readObject();
        } catch (Exception e) {
            System.out.println("读取expresses失败");
        }

        Socket socket2 = new Socket("127.0.0.1", 56604);
        InputStream inputStream2 = socket2.getInputStream();
        try (ObjectInputStream expressPlaceInput = new ObjectInputStream(inputStream2)) {
            Dao.expressPlaces = (HashSet<ExpressPlace>) expressPlaceInput.readObject();
        } catch (Exception e) {
            System.out.println("读取expressPlaces失败");
        }

    }
}
